from binn import *
from binn_iter import BinnIter, binn_iter_init
from binn_list import BinnList

lib.binn_object_set_bool.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_bool]


def binn_object_set_bool(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_bool(binn, key, val)


lib.binn_object_set_bool.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_bool]


def binn_object_set_bool(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_bool(binn, key, val)


lib.binn_object_uint8.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_uint8.restype = ct.c_uint8


def binn_object_uint8(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_uint8(binn, key)


lib.binn_object_set_uint8.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_uint8]


def binn_object_set_uint8(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_uint8(binn, key, val)


lib.binn_object_set_uint8.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_uint8]


def binn_object_set_uint8(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_uint8(binn, key, val)


lib.binn_object_uint8.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_uint8.restype = ct.c_uint8


def binn_object_uint8(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_uint8(binn, key)


lib.binn_object_set_uint16.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_uint16]


def binn_object_set_uint16(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_uint16(binn, key, val)


lib.binn_object_uint16.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_uint16.restype = ct.c_uint16


def binn_object_uint16(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_uint16(binn, key)


lib.binn_object_set_uint32.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_uint32]


def binn_object_set_uint32(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_uint32(binn, key, val)


lib.binn_object_uint32.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_uint32.restype = ct.c_uint32


def binn_object_uint32(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_uint32(binn, key)


lib.binn_object_set_uint64.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_uint64]


def binn_object_set_uint64(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_uint64(binn, key, val)


lib.binn_object_uint64.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_uint64.restype = ct.c_uint64


def binn_object_uint64(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_uint64(binn, key)


lib.binn_object_int8.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_int8.restype = ct.c_int8


def binn_object_int8(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_int8(binn, key)


lib.binn_object_set_int16.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_int16]


def binn_object_set_int16(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_int16(binn, key, val)


lib.binn_object_int16.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_int16.restype = ct.c_int16


def binn_object_int16(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_int16(binn, key)


lib.binn_object_set_int32.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_int32]


def binn_object_set_int32(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_int32(binn, key, val)


lib.binn_object_int32.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_int32.restype = ct.c_int32


def binn_object_int32(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_int32(binn, key)


lib.binn_object_set_int64.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_int64]


def binn_object_set_int64(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_int64(binn, key, val)


lib.binn_object_int64.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_int64.restype = ct.c_int64


def binn_object_int64(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_int64(binn, key)


lib.binn_object_set_float.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_float]


def binn_object_set_float(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_float(binn, key, val)


lib.binn_object_float.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_float.restype = ct.c_float


def binn_object_float(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_float(binn, key)


lib.binn_object_set_double.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_double]


def binn_object_set_double(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_double(binn, key, val)


lib.binn_object_double.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_double.restype = ct.c_double


def binn_object_double(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_double(binn, key)


lib.binn_object_set_str.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_char_p]


def binn_object_set_str(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if isinstance(val, str):
        val = val.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_str(binn, key, val)


lib.binn_object_str.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_str.restype = ct.c_char_p


def binn_object_str(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_str(binn, key).decode()


lib.binn_object_set_blob.argtypes = [
    ct.c_voidp, ct.c_char_p, ct.c_voidp, ct.c_char_p
]


def binn_object_set_blob(binn, key, val, size):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_blob(binn, key, val, size)


lib.binn_object_set_map.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_voidp]


def binn_object_set_map(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_map(binn, key, val)


lib.binn_object_map.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_map.restype = ct.c_voidp


def binn_object_map(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_map(binn, key)


lib.binn_object_set_object.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_voidp]


def binn_object_set_object(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_object(binn, key, val)


lib.binn_object_object.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_object.restype = ct.c_voidp


def binn_object_object(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_object(binn, key)


lib.binn_object_set_list.argtypes = [ct.c_voidp, ct.c_char_p, ct.c_voidp]


def binn_object_set_list(binn, key, val):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_set_list(binn, key, val)


lib.binn_object_list.argtypes = [ct.c_voidp, ct.c_char_p]
lib.binn_object_list.restype = ct.c_voidp


def binn_object_list(binn, key):
    if isinstance(key, str):
        key = key.encode('utf-8')
    if not isinstance(binn, ct.c_voidp):
        binn = ct.c_voidp(binn)
    return lib.binn_object_list(binn, key)

class BinnObj():

    def __init__(self, *args):
        if len(args) == 1:
            self._binn = args[0]
            self._own = False
        else:
            self._binn = binn_object()
            self._own = True

    def __del__(self):
        if self._own:
            binn_free(self._binn)

    def begin(self):
        binn_iter = BinnIter(BINN_OBJECT)
        binn_iter_init(binn_iter.iter, self.binn, BINN_OBJECT)
        return binn_iter

    @property
    def binn(self):
        return self._binn

    def set_uint8(self, iden, val):
        return binn_object_set_uint8(self._binn, iden, val)

    def get_uint8(self, iden):
        return binn_object_uint32(self._binn, iden)

    def set_uint16(self, iden, val):
        return binn_object_set_uint32(self._binn, iden, val)

    def get_uint16(self, iden):
        return binn_object_uint32(self._binn, iden)

    def set_uint32(self, iden, val):
        return binn_object_set_uint32(self._binn, iden, val)

    def get_uint32(self, iden):
        return binn_object_uint32(self._binn, iden)

    def set_uint64(self, iden, val):
        return binn_object_set_uint64(self._binn, iden, val)

    def get_uint64(self, iden):
        return binn_object_uint64(self._binn, iden)

    def set_int8(self, iden, val):
        return binn_object_set_int8(self._binn, iden, val)

    def get_int8(self, iden):
        return binn_object_int32(self._binn, iden)

    def set_int16(self, iden, val):
        return binn_object_set_int32(self._binn, iden, val)

    def get_int16(self, iden):
        return binn_object_int32(self._binn, iden)

    def set_int32(self, iden, val):
        return binn_object_set_int32(self._binn, iden, val)

    def get_int32(self, iden):
        return binn_object_int32(self._binn, iden)

    def set_int64(self, iden, val):
        return binn_object_set_int64(self._binn, iden, val)

    def get_int64(self, iden):
        return binn_object_int64(self._binn, iden)

    def set_float(self, iden, val):
        return binn_object_set_float(self._binn, iden, val)

    def get_float(self, iden):
        return binn_object_float(self._binn, iden)

    def set_double(self, iden, val):
        return binn_object_set_double(self._binn, iden, val)

    def get_double(self, iden):
        return binn_object_double(self._binn, iden)

    def set_str(self, iden, val):
        if isinstance(val, str):
            val = val.encode('utf-8')
        return binn_object_set_str(self._binn, iden, val)

    def get_str(self, iden):
        return binn_object_str(self._binn, iden)

    def set_ndarr(self, iden, val):
        arr_as_voidp = val.ctypes.data_as(ct.c_voidp)
        size = val.size * val.itemsize
        return binn_object_set_blob(self._binn, iden, arr_as_voidp, size)

    def get_ndarr(self, iden, typ):
        ptr, size = binn_object_blob(self._binn, iden)
        if typ == 'f32':
            nitems = size // ct.sizeof(ct.c_float)
            buf = (ct.c_float * nitems)(10)
            ct.memmove(buf, ptr, size)
            return np.frombuffer(buf, np.float32)
        return

    def set_obj(self, iden, binn_obj):
        return binn_object_set_object(self._binn, iden, binn_obj._binn)

    def get_obj(self, iden):
        binn_obj = binn_object_object(self._binn, iden)
        return BinnObj(binn_obj)

    def set_map(self, iden, binn_map):
        return binn_object_set_map(self._binn, iden, binn_map._binn)

    def get_map(self, iden):
        from binn_map import BinnMap
        binn_mao = binn_object_object(self._binn, iden)
        return BinnMap(binn_map)

    def set_list(self, iden, binn_list):
        return binn_object_set_list(self._binn, iden, binn_list._binn)

    def get_list(self, iden):
        from binn_list import BinnList
        binn_list = binn_object_list(self._binn, iden)
        return BinnList(binn_obj)
